<template>
	<view class="content">
		<view class="content-box" @touchstart="touchstart" id="content-box">
			<!-- 背景图- 定位方式 -->
			<!-- <image class="content-box-bg" :src="_user_info.chatBgImg" :style="{ height: imgHeight }"></image> -->
			<view class="message" v-for="(item, index) in messageList" :key="index">
				<view class="message-item" :class="item.isItMe ? 'right' : 'left'">
					<image class="img" :src="item.isItMe ? '/static/image/defaultAvater.png' : '/static/image/logo.png'" mode="">
					</image>
					<!-- 第一次消息提示 -->
					<view class="content content_first" :class="item.isItMe ? 'right_content' : 'left_content'"
						v-if="item.contentType == 0">
						<view>{{ item.title }}</view>
						<view class="d-flex flex-wrap gap-2 mt-2">
							<view class="promptList" v-for="(Pitem, pindex) in item.promptList">{{ Pitem }}</view>
						</view>
					</view>
					<!-- contentType = 1 文本 -->
					<view class="content" :class="item.isItMe ? 'right_content' : 'left_content'" v-if="item.contentType == 1"
						v-html="item.content" @longpress="handleCopy(item.text)">
					</view>
					<!-- contentType = 2 语音 -->
					<view v-if="item.contentType == 2" class="d-flex flex-column j-end a-end">
						<view class="content contentType2" :class="[{ 'content-type-right': item.isItMe }]" @tap="handleAudio(item)"
							hover-class="contentType2-hover-class" :style="{width:`${130+(item.contentDuration*10)}rpx`}">
							<view class="voice_icon" :class="[
									{ voice_icon_right: item.isItMe },
									{ voice_icon_right_an: item.anmitionPlay && item.isItMe },
								]"></view>
							<view class="voice_icon"></view>
							<view>{{ item.contentDuration }}''</view>
						</view>
						<view class="content convert mt-2" :class="[{ 'content-type-right': item.isItMe }]"
							@longpress="handleCopy(item.text)">{{ item.convertText }}</view>
						<!-- 记账内容 -->
					</view>
					<view class="flex-1" :class="item.isItMe ? 'right_content' : 'left_content'" v-if="item.contentType == 4"
						style="color: black;">
						<view class="content" style="color: black;">
							<view class="d-flex j-sb a-center">
								<view class="font-26">记账</view>
								<view class="grey_color font-24">{{item.eventTime}}</view>
							</view>
							<view class="mt-3 d-flex j-sb a-center">
								<view class="d-flex j-sb a-center">
									<view class="avatar_img">
										<image :src="getImg(item)" mode=""></image>
									</view>
									<view class="ml-2">
										<view class="font-26 font-weight-600">{{ item.eventType ? item.eventType : '--'}}</view>
										<view class="font-24">{{ item.remark ? item.remark : '--'}}</view>
									</view>
								</view>
								<view class="price font-24" :class="item.inOut === 1 ? 'expense':'income'">￥
									{{ item.inOut === 1 ? '-' : '+' }}
									{{ item.amount ? item.amount : '--' }}
								</view>
							</view>
						</view>
						<view class="grey_color d-flex mt-3 ml-3">
							<view class="btn_bg d-flex j-center a-center" @click="goToDetail(item)">修改分类</view>
							<view class="ml-3 btn_bg d-flex j-center a-center" @click="handleDelete(item, index)">删除账单</view>
						</view>
					</view>
				</view>
			</view>

			<!-- 底部聊天输入框 -->
			<view class="input-box" :style="{bottom: `${bottom}px`}">
				<view class="input-box-flex">
					<!-- #ifndef H5 -->
					<image v-if="chatType === 'voice'" class="icon_img icon_voice_img" src="/static/microphone.png"
						@click="switchChatType('keyboard')"></image>
					<image v-if="chatType === 'keyboard'" class="icon_img" src="/static/keyboard.png"
						@click="switchChatType('voice')"></image>
					<!-- #endif -->
					<view class="input-box-flex-grow">
						<input v-if="chatType === 'voice'" type="text" class="content" id="input" v-model="formData.content"
							:hold-keyboard="true" :confirm-type="'send'" :confirm-hold="true" placeholder-style="color:#DDDDDD;"
							:cursor-spacing="10" @confirm="sendMsg(null)" :adjust-position="false" @focus="inputBindFocus"
							@blur="inputBindBlur" />
						<view class="voice_title" v-if="chatType === 'keyboard'" style="background: #eceff5"
							@touchstart.stop.prevent="requestPermissionAndStart" @touchmove.stop.prevent="moveVoice"
							@touchend.stop="stopRecording" @touchcancel.stop="cancelVoice">
							{{ voiceTitle }}
						</view>
					</view>
					<!-- 发送按钮 -->
					<view v-if="chatType === 'voice'" @click="sendMsg(null)" class="voice_btn">发 送</view>
				</view>
			</view>

			<!-- //语音动画 -->
			<view class="voice_an" v-if="recording">
				<view class="text">{{voiceIconText}}</view>
				<view class="voice_an_icon">
					<view id="one" class="wave"></view>
					<view id="two" class="wave"></view>
					<view id="three" class="wave"></view>
					<view id="four" class="wave"></view>
					<view id="five" class="wave"></view>
					<view id="six" class="wave"></view>
					<view id="seven" class="wave"></view>
					<view id="eight" class="wave"></view>
					<view id="night" class="wave"></view>
					<view id="ten" class="wave"></view>
					<view id="elevent" class="wave"></view>
					<view id="twelve" class="wave"></view>
					<view id="thirteen" class="wave"></view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	import {
		shareMixins
	} from '@/common/share.js'
	import {
		aiAccount,
		delAccount,
		getAsrKey,
		getCosKey,
		getMessageList
	} from "@/api/index.js"
	import {
		INCOM_LIST,
		EXPEND_LIST
	} from "@/constant/index.js"
	export default {
		mixins: [shareMixins],
		data() {
			return {
				fromUserInfo: {},
				formData: {
					content: '',
					limit: 15,
					index: 1
				},
				messageList: [],
				imgHeight: '1000px',
				mpInputMargin: false, //适配微信小程序 底部输入框高度被顶起的问题
				chatType: "voice", // 图标类型 'voice'语音 'keyboard'键盘
				voiceTitle: '按住 说话',
				Recorder: uni.getRecorderManager(),
				Audio: uni.createInnerAudioContext(),
				recording: false, //标识是否正在录音
				isStopVoice: false, //加锁 防止点击过快引起的当录音正在准备(还没有开始录音)的时候,却调用了stop方法但并不能阻止录音的问题
				voiceInterval: null,
				voiceTime: 0, //总共录音时长
				canSend: true, //是否可以发送
				PointY: 0, //坐标位置
				voiceIconText: "正在录音...",
				showFunBtn: false, //是否展示功能型按钮
				AudioExam: null, //正在播放音频的实例
				userInfo: this.$store.state.user.userInfo,
				temData: null,
				base64Data: null,
				incomeList: INCOM_LIST, //收入列表
				expendList: EXPEND_LIST, //支出列表
				bottom: 0, // 输入框距离页面底部距离（键盘高度px）
				recorderManager: null, // 录音管理器
				recordPath: '' // 录音文件路径
			};
		},
		methods: {
			inputBindFocus(e) {
				this.bottom = e.detail.height
			},
			inputBindBlur() {
				this.bottom = 0
			},
			handleCopy(content) {
				uni.setClipboardData({
					data: content,
					success() {
						uni.showToast({
							title: '复制成功',
							icon: 'success'
						})
					},
					fail() {
						uni.showToast({
							title: '复制失败',
							icon: 'error'
						})
					}
				});
			},
			getImg(item) {
				if (item.inOut === 1) { // 支出
					for (let iten of this.expendList) {
						if (iten.text === item.eventType) {
							return iten.activeIcon
						}
					}
				} else { // 收入
					for (let iten of this.incomeList) {
						if (iten.text === item.eventType) {
							return iten.activeIcon
						}
					}
				}
			},
			//切换语音或者键盘方式
			switchChatType(type) {
				this.formData.content = '';
				this.chatType = type;
				this.showFunBtn = false;
			},
			//切换功能性按钮
			switchFun() {
				this.chatType = 'keyboard'
				this.showFunBtn = !this.showFunBtn;
				uni.hideKeyboard()
			},
			//发送消息
			async sendMsg(data) {
				uni.hideKeyboard();
				const params = {
					hasBeenSentId: Date.now(), //已发送过去消息的id
					content: this.formData.content,
					text: this.formData.content,
					fromUserHeadImg: this.userInfo.avatarUrl, //用户头像
					// fromUserId: this._user_info.id,
					isItMe: true, //true此条信息是我发送的  false别人发送的
					createTime: Date.now(),
					contentType: 1,
				};
				if (data) {
					if (data.contentType == 2) { //说明是发送语音
						params.content = data.content;
						params.contentType = data.contentType;
						params.contentDuration = data.contentDuration;
						this.convert(params.content).then(res => {
							this.formData.content = params.text = params.convertText = res || '识别失败'
							params.anmitionPlay = false;
							this.messageList.push(params);
							uni.setStorageSync('messageList', JSON.stringify(this.messageList))
							this.$nextTick(() => {
								this.formData.content = '';
								uni.pageScrollTo({
									scrollTop: 99999,
									duration: 100
								});
							})
							if (this.formData.content !== '识别失败' && this.formData.content !== '') {
								this.createAccount()
							} else {
								this.$nextTick(() => {
									this.formData.content = '';
									uni.pageScrollTo({
										scrollTop: 99999,
										duration: 100
									});
								})
							}
						}).catch(err => {
							this.formData.content = params.text = params.convertText = '识别失败'
							params.anmitionPlay = false;
							this.messageList.push(params);
							uni.setStorageSync('messageList', JSON.stringify(this.messageList))
							this.$nextTick(() => {
								this.formData.content = '';
								uni.pageScrollTo({
									scrollTop: 99999,
									duration: 100
								});
							})
						})
					}
				} else { // 文本
					if (!(this.formData.content).trim()) {
						//验证输入框书否为空字符传
						return;
					}
					this.messageList.push(params);
					uni.setStorageSync('messageList', JSON.stringify(this.messageList))
					this.createAccount()
				}

				this.$nextTick(() => {
					this.formData.content = '';
					// #ifdef MP-WEIXIN
					if (params.contentType == 1) {
						uni.pageScrollTo({
							scrollTop: 99999,
							duration: 0, //小程序如果有滚动效果 input的焦点也会随着页面滚动...
						});
					} else {
						setTimeout(() => {
							uni.pageScrollTo({
								scrollTop: 99999,
								duration: 0, //小程序如果有滚动效果 input的焦点也会随着页面滚动...
							});
						}, 150)
					}
					// #endif

					// #ifndef MP-WEIXIN
					uni.pageScrollTo({
						scrollTop: 99999,
						duration: 100
					});
					// #endif

					if (this.showFunBtn) {
						this.showFunBtn = false;
					}

					// #ifdef MP-WEIXIN 
					if (params.contentType == 1) {
						this.mpInputMargin = true;
					}
					// #endif
					//h5浏览器并没有很好的办法控制键盘一直处于唤起状态 而且会有样式性的问题
					// #ifdef H5
					uni.hideKeyboard();
					// #endif
				});
			},
			createAccount() {
				uni.showLoading({
					title: '加载中...'
				})
				const dataForm = {
					uid: this.userInfo.uid, //用户uid
					msg: this.formData.content
				}
				aiAccount(dataForm).then((res) => {
					if (res.head.code === '0000') {
						if (res.body.account) {
							const account = {
								contentType: 4,
								fromServiceHeadImg: '/static/image/defaultAvater.png',
								...res.body.bill
							}
							// 生成账单
							this.messageList.push(account);
							uni.setStorageSync('messageList', JSON.stringify(this.messageList))
						}
						if (res.body.reply) {
							let replyStr = `<div>${res.body.reply.replace(/\n/g, '<br>')}</div>`
							const reply = {
								text: res.body.reply,
								content: replyStr,
								isItMe: false,
								contentType: 1,
								fromServiceHeadImg: '../../static/image/defaultAvater.png'
							}
							this.messageList.push(reply);
							uni.setStorageSync('messageList', JSON.stringify(this.messageList))
						}
						uni.hideLoading()
					} else {
						uni.hideLoading()
						uni.showToast({
							title: res.head.msg,
							icon: 'error'
						})
					}
					this.$nextTick(() => {
						this.formData.content = '';
						uni.pageScrollTo({
							scrollTop: 99999,
							duration: 100,
							success() {}
						});
					})
				})
			},
			convert(path) {
				return new Promise((resolve, reject) => {
					wx.getFileSystemManager().readFile({
						filePath: path,
						encoding: 'base64',
						success: (fileRes) => {
							let plugin = requirePlugin("QCloudAIVoice");
							//设置腾讯云账号信息，其中appid（非微信appid）是数字，secret是字符串，
							plugin.setQCloudSecret(this.temData.appid, this.temData.asrData.Credentials.TmpSecretId, this
								.temData.asrData.Credentials.TmpSecretKey, true, this.temData.asrData.Credentials.Token);
							const frameBuffer = fileRes.data;
							const buf = wx.base64ToArrayBuffer(frameBuffer);
							plugin.sentenceRecognition({
								engSerViceType: '16k_zh',
								sourceType: 1,
								voiceFormat: 'mp3',
								data: frameBuffer,
								dataLen: buf.byteLength,
								success: function(data) {
									resolve(data.result)
								},
								fail: function(err) {
									reject(err.Error);
								}
							});
						},
						fail: function(err) {}
					});
				})
			},
			// 获取腾讯云语音识别临时密码
			fetchAsrKey() {
				const data = {
					uid: this.userInfo.uid, //用户uid
				}
				getAsrKey(data).then((res) => {
					// 腾讯云账号信息
					this.temData = res.body
				}).catch((err) => {
					uni.showToast({
						title: err
					})
				})

			},
			//用户触摸屏幕的时候隐藏键盘
			touchstart() {
				uni.hideKeyboard();
			},
			//关闭动画
			closeAnmition() {
				const hasBeenSentId = this.Audio.hasBeenSentId;
				const item = this.messageList.find(it => it.hasBeenSentId == hasBeenSentId);
				item.anmitionPlay = false;
			},
			// 跳转到修改账单
			goToDetail(item) {
				const serializedItem = encodeURIComponent(JSON.stringify(item));
				uni.navigateTo({
					url: `/pages/index/detail?accountDetails=${serializedItem}&date=${item.eventTime}`
				})
			},
			// 删除
			handleDelete(item, index) {
				uni.showModal({
					title: '提示',
					content: '确认删除账单吗？',
					success: res => {
						if (res.confirm) {
							delAccount(item.id, this.userInfo.uid).then(res => {
								if (res.head.code === '0000') {
									uni.showToast({
										title: '删除成功',
										icon: 'success'
									})
									this.messageList.splice(index, 1)
								}
							})
						}
					}
				})
			},
			/* 录音逻辑 start */
			//move 正在录音中
			moveVoice(e) {
				const PointY = e.touches[0].clientY
				const slideY = this.PointY - PointY;
				if (slideY > uni.upx2px(120)) {
					this.canSend = false;
					this.voiceIconText = '松开手指 取消发送 '
					this.recording = false;
				} else if (slideY > uni.upx2px(60)) {
					this.canSend = true;
					this.voiceIconText = '手指上滑 取消发送 '
					this.recording = false;
				} else {
					this.voiceIconText = '正在录音... '
				}
			},
			//录音被打断
			cancelVoice(e) {
				this.voiceTime = 0;
				this.voiceTitle = '按住 说话';
				this.canSend = false;
				this.Recorder.stop();
				this.Recorder.onStop(res => {
					uni.showToast({
						title: 'Recorder.onStop',
						icon: 'none'
					})
					clearInterval(this.voiceInterval);
					this.handleRecorder(res);
				});
			},
			//处理录音文件
			handleRecorder({
				tempFilePath,
				duration
			}) {
				let contentDuration;
				// #ifdef MP-WEIXIN
				this.voiceTime = 0;
				if (duration < 600) {
					this.voiceIconText = "说话时间过短";
					setTimeout(() => {
						this.recording = false;
					}, 200)
					return;
				}
				contentDuration = duration / 1000;
				// #endif

				this.recording = false;
				const params = {
					contentType: 2,
					content: tempFilePath,
					contentDuration: Math.ceil(contentDuration)
				};
				this.canSend && this.sendMsg(params);
			},
			//控制播放还是暂停音频文件
			handleAudio(item) {
				this.AudioExam = item;
				this.Audio.paused ? this.playAudio(item) : this.stopAudio(item);
			},
			//播放音频
			playAudio(item) {
				this.Audio.src = item.content;
				this.Audio.hasBeenSentId = item.hasBeenSentId;
				this.Audio.play();
				item.anmitionPlay = true;
			},
			//停止音频
			stopAudio(item) {
				item.anmitionPlay = false;
				this.Audio.src = '';
				this.Audio.stop();
			},
			requestPermissionAndStart() {
				uni.getSetting({
					success: (res) => {
						if (!res.authSetting['scope.record']) {
							// 没有录音权限，主动申请
							this.recording = false;
							uni.authorize({
								scope: 'scope.record',
								success: () => {
									// this.startRecording();
								},
								fail: () => {
									uni.showModal({
										title: '提示',
										content: '需要录音权限才能使用该功能，请前往设置开启。',
										success: (modalRes) => {
											if (modalRes.confirm) {
												uni.openSetting();
											}
										},
										fail: (err) => {
											uni.showToast({
												title: '录音权限失败',
												icon: 'none'
											})
										}
									});
								}
							});
						} else {
							// 已授权，开始录音
							this.startRecording();
						}
					},
				});
			},

			// 开始录音
			startRecording() {
				if (!this.recorderManager) {
					this.recorderManager = uni.getRecorderManager();
					this.recorderManager.onStop(this.onRecordingStop);
					this.recorderManager.onError(this.onRecordingError);
				}
				if (this.Audio && !this.Audio.paused) {
					//如果音频正在播放 先暂停。
					this.stopAudio(this.AudioExam)
				}
				this.recording = true;
				this.isStopVoice = false;
				this.canSend = true;
				this.voiceIconText = "正在录音..."
				this.voiceTitle = '松开 结束'
				// this.PointY = e.touches[0].clientY;

				// 开始录音
				this.recorderManager.start({
					duration: 60000, // 最长录音时长（单位：ms），这里是 60 秒
					sampleRate: 16000, // 采样率
					numberOfChannels: 1, // 声道
					encodeBitRate: 96000, // 编码码率
					format: 'mp3' // 音频格式
				});

				this.recording = true
			},

			// 停止录音
			stopRecording() {
				if (this.recorderManager) {
					this.isStopVoice = true; //加锁 确保已经结束录音并不会录制
					this.voiceTitle = '按住 说话'
					this.recording = false;
					this.recorderManager.stop();
				}
			},

			// 录音停止回调
			onRecordingStop(res) {
				this.recordPath = res.tempFilePath; // 保存录音文件路径
				clearInterval(this.voiceInterval);
				this.handleRecorder(res)
			},

			// 录音错误回调
			onRecordingError(err) {
				uni.showToast({
					title: '录音失败，请重试',
					icon: 'none'
				});
			},
			/* 录音逻辑 end */
		},
		onLoad() {
			let messageList = uni.getStorageSync('messageList')
			this.messageList = messageList ? JSON.parse(messageList) : []
			const appInfo = uni.getStorageSync('appInfo') ? JSON.parse(uni.getStorageSync('appInfo')) : null
			if (appInfo) {
				this.messageList[0] = {
					title: appInfo.appParams.guideMsg.promptTitle,
					promptList: appInfo.appParams.guideMsg.promptList,
					isItMe: false,
					contentType: 0,
					fromServiceHeadImg: '/static/image/defaultAvater.png'
				}
			}
			// 获取腾讯云语音识别临时密码
			this.fetchAsrKey()

			//音频停止事件
			this.Audio.onStop(e => {
				this.closeAnmition();
			});

			//音频播放结束事件
			this.Audio.onEnded(e => {
				this.closeAnmition();
			});

			this.$nextTick(() => {
				uni.pageScrollTo({
					scrollTop: 99999,
					duration: 100
				});
			})
		},
		onShow() {
			uni.$on('returnForm', form => {
				for (let item of this.messageList) {
					if (item.id) {
						if (item.id === form.id) {
							item.amount = form.amount
							item.eventType = form.eventType
							item.inOut = form.inOut
							item.remark = form.remark
							item.eventTime = form.eventTime
						}
					}
				}
				uni.setStorageSync('messageList', JSON.stringify(this.messageList))
			})
		},
		onReady() {
			//自定义返回按钮 因为原生的返回按钮不可阻止默认事件
			// #ifdef H5
			const icon = document.getElementsByClassName('uni-page-head-btn')[0];
			icon.style.display = 'none';
			// #endif

			uni.onKeyboardHeightChange(res => {
				if (res.height == 0) {
					// #ifdef MP-WEIXIN
					this.mpInputMargin = false;
					// #endif
				} else {
					this.showFunBtn = false;
				}
			});
		},
		beforeDestroy() {
			let messageList
			if (this.messageList.length > 100) {
				messageList = this.messageList.slice(this.messageList.length - 100)
				let index
				for (let i = 0; i < messageList.length; i++) {
					if (messageList[i].isItMe) {
						index = i
						break
					}
				}
				messageList = messageList.slice(index)
			} else {
				messageList = this.messageList
			}

			const data = {
				uid: this.userInfo.uid,
				extraData: {
					messageList
				}
			}
			uni.setStorageSync('messageList', JSON.stringify(messageList))
			getMessageList(data).then((res) => {})
		},
	};
</script>

<style lang="scss" scoped>
	@import './index.scss'
</style>